ADFA-5333 feat(dashboard): run the live update in the background - #493
Merged
luisguzman-adfa merged 4 commits intoAug 28, 2026
Merged
Conversation
The live REST dashboard update (dash-node >= 1.2.0) trapped the user behind a non-cancelable modal that polled for up to ~6.5 min. The rebuild already runs detached in the box (blue-green, returns 202), so hold nothing on the client. Hand off to a new DashboardRebuildService (foreground + notification): the user navigates freely while it POSTs the rebuild and polls status. Completion is the server's signal (done/error), not a time cap — the MAX_POLLS ceiling and the "taking longer than usual" message are gone. A visible dashboard card refreshes its version/pill in place on the service's completion broadcast. The proot bridge path (< 1.2.0) is unchanged; it stops the box and keeps its own guarded screen. Strings localized across all 33 locales.
The live REST dashboard update (dash-node >= 1.2.0) trapped the user behind a non-cancelable modal that polled for up to ~6.5 min, then showed a "taking longer than usual" timeout when a fixed cap expired. The rebuild already runs detached in the box (blue-green, returns 202), so hold nothing on the client and don't guess completion by a clock. Hand off to a new DashboardRebuildService (foreground + notification): the user navigates freely while it POSTs the rebuild and polls status. Completion is the server's signal (done/error), not a time cap — MAX_POLLS and the k2go_dash_live_timeout string are gone. State changes broadcast (running/done/error); a static isRunning() lets a card opened mid-update pick it up. In-app progress lives on the dashboard card, not only in the notification: while a rebuild runs, an indeterminate Material bar shows above Rebuild (disabled meanwhile), and the version chip/pill refresh in place on completion. The card re-derives state from the box on open, so even after a process kill it shows progress and re-owns the service (409 re-attach). The ongoing notification is not dismissible and does not auto-cancel on tap; tapping it deep-links to Module management > Dashboard (EXTRA_DASHBOARD_DETAIL, handled in onCreate and onNewIntent). On done/error it becomes a dismissible result. The proot bridge path (< 1.2.0) is unchanged; it stops the box and keeps its own guarded screen. Strings localized across all 33 locales.
…, mutual exclusion The live dash-node update (>= 1.2.0) trapped the user behind a non-cancelable modal that polled a fixed ~6.5 min budget and then showed a "taking longer than usual" timeout. The rebuild already runs detached in the box (blue-green, returns 202), so this moves it to the background and makes it observable, cancelable, and safely serialized against downloads. Background + completion by signal - New DashboardRebuildService (foreground + notification): the user navigates freely while it POSTs the rebuild and polls status. Completion is the server's signal (done/error) confirmable by the live version — no time cap. MAX_POLLS and k2go_dash_live_timeout are gone. In-app progress, not only a notification - The dashboard card shows an indeterminate Material bar (the rebuild has no percent) with a Cancel beside it; version chip/pill refresh in place on completion. The card re-derives state from the box on open, so even after a process kill it shows progress and re-owns the service (409 re-attach). The ongoing notification is non-dismissible, doesn't auto-cancel on tap, deep-links to Module management > Dashboard (EXTRA_DASHBOARD_DETAIL, handled in onCreate + onNewIntent), and carries a Cancel action. Clean cancel (device + dash-node) - Server: POST /system/dashboard/rebuild/cancel. rebuild-dashboard.sh records its phase (building/promoting) and session-leader pid; cancel while "building" signals the detached group (its EXIT/TERM trap purges staging), leaving the live dashboard as it was; refused while "promoting", and the script ignores INT/TERM through the swap so it is never interrupted mid-flight. dash-node 1.2.8 -> 1.2.9 (+ CHANGELOG). - Device: DashboardClient.rebuildCancel + a Cancel action/button; on success the service stops and the card re-enables Rebuild; if too late or unreachable it says so and the update finishes. Mutual exclusion (a live update and a live download share dash-node; the update restarts it and would break an in-flight download) - EnvironmentLock gains Holder.DASHBOARD, so deep-env ops (backup/restore/clone/install) defer to an in-flight update automatically; the three live-download starts (ZIM/Books/ Kolibri), which don't consult the lock, get an explicit refusal (k2go_busy_dashboard). The proot bridge path (< 1.2.0) is unchanged. New strings localized across all 33 locales.
Review follow-ups on the background dashboard update: - Re-own can no longer start an unintended rebuild. DashboardRebuildService gains ACTION_ATTACH / attach(): the card re-owns an already-running rebuild by polling to completion, never POSTing /rebuild, so a rebuild that finishes in the gap between the status check and re-attach can't trigger a fresh run. - The reverse gate now covers auto-drains, not just user taps. ZimProvisioner and BooksProvisioner drain() and KolibriProvisioner canDrainNow() defer while DashboardRebuildService.isRunning(), so a banked wishlist can't auto-start a live download mid-rebuild (which the dash-node restart would disrupt). - Cancel is hardened on both ends. rebuild-dashboard.sh traps INT/TERM to on_cancel, which sets the status to idle before cleanup, so a canceled build never leaves a wedged "running" (promote stays signal-proof). The cancel endpoint verifies the recorded pid is actually rebuild-dashboard.sh (via
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Run the live dashboard (dash-node) update in the background.
The dashboard is a REST API with a blue-green self-rebuild: the box does the work
detached and returns 202 at once. The app, though, held the user behind a
non-cancelable modal polling for ~6.5 min, then showed a "taking longer than usual"
timeout when a fixed cap expired.
This change (live REST path only, dash-node >= 1.2.0):
The user can leave; a snackbar confirms it started.
MAX_POLLS cap and the k2go_dash_live_timeout string are removed.
internal, explicit-package completion broadcast (registered only while STARTED).
Out of scope / unchanged: the proot bridge path (< 1.2.0) still stops the box and
uses its own guarded progress screen. No server change — the rebuild endpoints were
already detached + status-polled.
Verification: reviewed for the FGS startForeground contract (idempotent start on
re-tap) and receiver lifecycle; XML validated across all 33 locale files. No Android
build in this environment. New strings are machine-translated — flagging bn, gu, ta,
sw, az, yo, sr for native review.
Open question (see review): backgrounding removes the modal's implicit serialization,
so a user could start a box-stopping op during a live rebuild. Deciding whether to
gate via EnvironmentLock now or as a follow-up.